package com.reebake.ideal.cloud.config;

import cn.hutool.core.util.ClassUtil;
import com.reebake.ideal.cloud.properties.FeignClientRegisterProperties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.cloud.openfeign.FeignClientBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class FeignClientBuilderConfig implements BeanFactoryPostProcessor, ApplicationContextAware, EnvironmentAware {

    private static FeignClientBuilder builder;
    private List<FeignClientRegisterProperties> feignClientRegisterPropertiesList = new ArrayList<>();

    /**
     * 手动生成FeignClient
     *
     * @param clazz    需要注册成FeignClient的接口类
     * @param name 名称
     * @param contextId 上下文编号
     * @param path 路径
     */
    public static <T> T getFeignClient(Class<T> clazz, String name, String contextId, String path) {
        FeignClientBuilder.Builder<T> feignClientBuilder = builder.forType(clazz, name);
        return feignClientBuilder.contextId(contextId).path(path).build();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        builder = new FeignClientBuilder(applicationContext);
    }

    @Override
    public void setEnvironment(Environment environment) {
        String propKey = "feign-clients";
        BindResult<List<FeignClientRegisterProperties>> bindResult = Binder.get(environment).bind(propKey, Bindable.listOf(FeignClientRegisterProperties.class));
        if (bindResult.isBound()) {
            this.feignClientRegisterPropertiesList = bindResult.get();
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        for (FeignClientRegisterProperties feignClientRegisterProperties : feignClientRegisterPropertiesList) {
            String name = feignClientRegisterProperties.getName();
            String path = feignClientRegisterProperties.getPath();
            for (String basePackage : feignClientRegisterProperties.getBasePackages()) {
                feignClientRegisterProperties.getTypes().addAll(ClassUtil.scanPackage(basePackage));
            }

            for (Class<?> clazz : feignClientRegisterProperties.getTypes()) {
                String contextId = clazz.getSimpleName();
                String beanName = contextId.substring(0, 1).toLowerCase() + contextId.substring(1);
                if (beanFactory.containsBean(beanName)) {
                    continue;
                }
                Object bean = getFeignClient(clazz, name, contextId, path);
                beanFactory.autowireBean(bean);
                beanFactory.registerSingleton(beanName, bean);
            }
        }
    }
}



